from sqlalchemy import Table, Column, Integer, String, Boolean, MetaData, ForeignKey, Text
from sqlalchemy.orm import mapper
from sqlalchemy.orm import relation, backref

from crv.model import DeclarativeBase, metadata, DBSession

from attr import AttrObj, AttrContainer
from rp import RP,Maker,MakerAttr,VMMaker,ProfileMaker,ClientMaker,RPAttr,MakerAttr
from crvmodel import Cluster,VM,RoleDef,Role,RoleDefAttr,RoleAttr,VMAttr,ClusterAttr,Message

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
# Controller Messages
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

tbMessage = Table('Message', metadata,
                  Column('Message_ID',Integer,primary_key=True),
                  Column('message',String(128),nullable=False),
                  Column('messageAbout',Integer,nullable=False), #id of vm or role that this is about
                  Column('messageInfo',Integer), #used for number of extra workers for scaling, can be null
                  )

mapper(Message,tbMessage);

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
# Cluster
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

tbClusterAttr=Table('ClusterAttr',metadata,
               Column('ClusterAttr_ID',Integer,primary_key=True),
               Column('Cluster_ID',Integer,ForeignKey('Cluster.Cluster_ID')),
               Column('name',String(128),nullable=False),
               Column('value',Text),
               Column('doc',Text)                
               )

tbCluster=Table('Cluster',metadata,
                Column('Cluster_ID',Integer,primary_key=True),
                Column('status',Integer,nullable=False),
                )

#ClusterAttr
mapper(ClusterAttr,tbClusterAttr)

#Cluster
#  1 cluster - many ClusterAttr
mapper(Cluster,tbCluster,
       properties={
    'attr':relation(ClusterAttr,
                    backref='cluster',cascade="all"),    
    })

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
# RoleDef
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

tbRoleDefAttr=Table('RoleDefAttr',metadata,
               Column('RoleDefAttr_ID',Integer,primary_key=True),
               Column('RoleDef_ID',Integer,ForeignKey('RoleDef.RoleDef_ID')),
               Column('name',String(128),nullable=False),
               Column('value',Text),
               Column('doc',Text)                
               )

tbRoleDef=Table('RoleDef',metadata,
                Column('RoleDef_ID',Integer,primary_key=True),
#                Column('dummyVal',Boolean), #SQLite does not support empty insert, so adding a dummy column to make the insert non-empty
                )

# Defile RoleDef's self-referring many-many mapping
tbRoleDefDep=Table('RoleDefDep',metadata,
          Column('RoleDef_Receiver',Integer,ForeignKey('RoleDef.RoleDef_ID')),
          Column('RoleDef_Provider',Integer,ForeignKey('RoleDef.RoleDef_ID'))
          )

tbRoleDefLocalDep=Table('RoleDefLocalDep',metadata,
          Column('RoleDefLocal_Receiver',Integer,ForeignKey('RoleDef.RoleDef_ID')),
          Column('RoleDefLocal_Provider',Integer,ForeignKey('RoleDef.RoleDef_ID'))
          )

#RoleDefAttr
mapper(RoleDefAttr,tbRoleDefAttr)

#RoleDef
#  (self-refer many-many dependOn)
#  (self-refer many-many dependOnLocal)
#  (1 RoleDef - Many RoleDefAttr)

mapper(RoleDef,tbRoleDef,properties={
    'attr':relation(RoleDefAttr,
                    backref='role',cascade="all"),    
    'dependOn':relation(RoleDef,secondary=tbRoleDefDep,primaryjoin=tbRoleDef.c.RoleDef_ID==tbRoleDefDep.c.RoleDef_Receiver,secondaryjoin=tbRoleDefDep.c.RoleDef_Provider==tbRoleDef.c.RoleDef_ID,cascade="save-update",backref="dependBy"),
    'dependOnLocal':relation(RoleDef,secondary=tbRoleDefLocalDep,primaryjoin=tbRoleDef.c.RoleDef_ID==tbRoleDefLocalDep.c.RoleDefLocal_Receiver,secondaryjoin=tbRoleDefLocalDep.c.RoleDefLocal_Provider==tbRoleDef.c.RoleDef_ID,cascade="save-update",backref="dependByLocal")
    })

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
# VM
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

tbVMAttr=Table('VMAttr',metadata,
               Column('VMAttr_ID',Integer,primary_key=True),
               Column('VM_ID',Integer,ForeignKey('VM.VM_ID')),
               Column('name',String(128),nullable=False),
               Column('value',Text),
               Column('doc',Text)                
               )

tbVM=Table('VM',metadata,
           Column('VM_ID',Integer,primary_key=True),
           Column('RP_ID',Integer,ForeignKey('RP.RP_ID')),               
           Column('status',Integer,nullable=False),
           )

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Mapping of things
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

#VMAttr
mapper(VMAttr,tbVMAttr)


#VM
# 1 VM - Many VMAttr
# many VM - 1 RP
mapper(VM,tbVM,
       properties={
    'attr':relation(VMAttr,backref='vm',cascade="all"),
    'rp':relation(RP,backref='vm',cascade="save-update"),
    })


# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
# Role
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

tbRoleAttr=Table('RoleAttr',metadata,
               Column('RoleAttr_ID',Integer,primary_key=True),
               Column('Role_ID',Integer,ForeignKey('Role.Role_ID')),
               Column('name',String(128),nullable=False),
               Column('value',Text),
               Column('doc',Text)                
               )

tbRole=Table('Role',metadata,
             Column('Role_ID',Integer,primary_key=True),
             Column('RoleDef_ID',Integer,ForeignKey('RoleDef.RoleDef_ID')),
             Column('VM_ID',Integer,ForeignKey('VM.VM_ID')),             
             Column('status',Integer,nullable=False),
             )

# Create Role's self-referring many-many mapping
tbRoleDep=Table('RoleDep',metadata,
          Column('Role_Receiver',Integer,ForeignKey('Role.Role_ID')),
          Column('Role_Provider',Integer,ForeignKey('Role.Role_ID'))
          )

tbRoleLocalDep=Table('RoleLocalDep',metadata,
          Column('RoleLocal_Receiver',Integer,ForeignKey('Role.Role_ID')),
          Column('RoleLocal_Provider',Integer,ForeignKey('Role.Role_ID'))
          )


# table for n-m mapping of Cluster-Role
tbClusterRole = Table('ClusterRole', metadata,
                      Column('Cluster_ID', Integer, ForeignKey('Cluster.Cluster_ID'), primary_key = True),
                      Column('Role_ID', Integer, ForeignKey('Role.Role_ID'), primary_key = True))                      


#RoleAttr
mapper(RoleAttr,tbRoleAttr)

#Role, mappings:
#  (many Role - many Role, dependOn)
#  (many Role - many Role, dependOnLocal)
#  (1 Role - many RoleAttr)
#  (Many Role - 1 VM)
#  (Many Role - Many Cluster)
#  (many Role - 1 RoleDef )
mapper(Role,tbRole,
       properties={
    'dependOn':relation(Role,secondary=tbRoleDep,primaryjoin=tbRole.c.Role_ID==tbRoleDep.c.Role_Receiver,secondaryjoin=tbRoleDep.c.Role_Provider==tbRole.c.Role_ID,cascade="save-update",backref='dependBy'),
    'dependOnLocal':relation(Role,secondary=tbRoleLocalDep,primaryjoin=tbRole.c.Role_ID==tbRoleLocalDep.c.RoleLocal_Receiver,secondaryjoin=tbRoleLocalDep.c.RoleLocal_Provider==tbRole.c.Role_ID,cascade="save-update",backref='dependByLocal'),
    'roleDef':relation(RoleDef,cascade="save-update"), #No backref since we don't need to know what Roles a RoleDef has
    'vm':relation(VM,backref='role',cascade="save-update"),
    'cluster':relation(Cluster,secondary=tbClusterRole,
                       backref='role',cascade="save-update"),   
    'attr':relation(RoleAttr,backref='role',cascade="all"),
    })


# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
# RP, Maker
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #


tbRP=Table('RP',metadata,
           Column('RP_ID',Integer,primary_key=True),
#           Column('dummyVal',Boolean), #SQLite does not support empty insert, so adding a dummy column to make the insert non-empty
           )

tbRPAttr=Table('RPAttr',metadata,
                 Column('RPAttr_ID',Integer,primary_key=True),
                 Column('RP_ID',Integer,ForeignKey('RP.RP_ID')),
                 Column('name',String(128),nullable=False),
                 Column('value',Text),
                 Column('doc',Text)
                 )

tbMaker=Table('Maker',metadata,
              Column('Maker_ID',Integer,primary_key=True),
#              Column('RP_ID',Integer,ForeignKey('RP.RP_ID') ),
              Column('type',String(128),nullable=False) #type for mapping multiple classes into the same table
           )

tbMakerAttr=Table('MakerAttr',metadata,
                 Column('MakerAttr_ID',Integer,primary_key=True),
                 Column('Maker_ID',Integer,ForeignKey('Maker.Maker_ID')),
                 Column('name',String(128),nullable=False),
                 Column('value',Text),
                 Column('doc',Text)
                 )

#MakerAttr
mapper(MakerAttr,tbMakerAttr)

#RPAttr
mapper(RPAttr,tbRPAttr)

#Maker
#  1 maker - many MakerAttr
makerMapper = mapper(Maker,tbMaker,
                     polymorphic_on=tbMaker.c.type, polymorphic_identity='maker',
                     properties={ 'attr':relation(MakerAttr,
                                                  backref='maker',cascade="all"),    
                                  })

vmmakerMapper = mapper(VMMaker,inherits=makerMapper, polymorphic_identity='maker_vm')
clientmakerMapper = mapper(ClientMaker,inherits=makerMapper, polymorphic_identity='maker_client')
profilemakerMapper = mapper(ProfileMaker,inherits=makerMapper, polymorphic_identity='maker_profile')


tbRPMakerDep=Table('RPMakerDep',metadata,
          Column('RP_ID',Integer,ForeignKey('RP.RP_ID')),
          Column('Maker_ID',Integer,ForeignKey('Maker.Maker_ID'))
          )

#RP
# many RP - many Maker
# 1 RP - many RPAttr

mapper(RP,tbRP,
       properties={'attr':relation(RPAttr,backref='rp',cascade="all"),
                   'makers':relation(Maker,backref='rp',cascade="save-update"),
#                   'vm':relation(VM, backref='rp', cascade="all"),
                   'makers':relation(Maker,secondary=tbRPMakerDep,primaryjoin=tbRP.c.RP_ID==tbRPMakerDep.c.RP_ID,secondaryjoin=tbRPMakerDep.c.Maker_ID==tbMaker.c.Maker_ID,cascade="save-update",backref='rps'),
                   })

from centos5_puppet_clientmaker import CentOS5_Puppet_ClientMaker
from dummyvmmaker import DummyVMMaker
from eucavmmaker import EucaVMMaker
from puppetprofilemaker import Puppet_ProfileMaker

mapper(CentOS5_Puppet_ClientMaker,inherits=clientmakerMapper, polymorphic_identity='maker_client_centos5puppet')
mapper(DummyVMMaker,inherits=vmmakerMapper, polymorphic_identity='maker_vm_dummy')
mapper(EucaVMMaker,inherits=vmmakerMapper, polymorphic_identity='maker_vm_euca')
mapper(Puppet_ProfileMaker,inherits=profilemakerMapper, polymorphic_identity='maker_profile_puppet')
